﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace ECommon.Helper
{
    /// <summary>
    /// xml工具
    /// </summary>
    internal static class XmlHelper
    {
        /// <summary>
        /// 直接根据xml的节点路径获取节点值
        /// </summary>
        /// <param name="nodeXPath">xml节点路径</param>
        /// <param name="xmlFilePathOrContent">xml文件路径或文件内容</param>
        /// <returns>节点值字符串，可空</returns>
        /// <exception cref="ArgumentException">变量错误异常</exception>
        private static string GetNode(string nodeXPath, string xmlFilePathOrContent)
        {
            string res = string.Empty;
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlFilePathOrContent);
            if (xmlDoc == null)
            {
                xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlFilePathOrContent);
            }
            if (xmlDoc == null)
            {
                throw new ArgumentException("xml文件路径或内容错误");
            }
            else
            {
                XmlNode node = xmlDoc.SelectSingleNode(nodeXPath);
                if (node == null)
                {
                    throw new ArgumentException(string.Format("没有找到节点：{0}", nodeXPath));
                }
                else
                {
                    string[] tmp = node.InnerText.Split(new char[] { '\t', '\r', '\n', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (tmp != null && tmp.Length > 0)
                    {
                        res = string.Join(" ", tmp);
                    }
                }
            }
            return res;
        }

        /// <summary>
        /// 直接根据xml的节点路径设置节点值
        /// </summary>
        /// <param name="nodeXPath">xml节点路径</param>
        /// <param name="xmlFilePath">xml文件路径</param>
        /// <param name="nodeValue">xml节点值</param>
        private static void SetNode(string nodeXPath, string xmlFilePath, string nodeValue)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlFilePath);
            if (xmlDoc == null)
            {
                throw new ArgumentException("xml文件路径错误");
            }
            XmlNode node = xmlDoc.SelectSingleNode(nodeXPath);
            if (node == null)
            {
                throw new ArgumentException(string.Format("没有找到节点：{0}", nodeXPath));
            }
            node.InnerText = nodeValue;
            xmlDoc.Save(xmlFilePath);
        }

        /// <summary>
        /// 直接根据xml的节点路径设置节点值，同时刷新原有xml内容
        /// </summary>
        /// <param name="nodeXPath">xml节点路径</param>
        /// <param name="xmlContent">xml文本内容</param>
        /// <param name="nodeValue">xml节点值</param>
        /// <returns>设置结果</returns>
        private static string SetNodeAndRefresh(string nodeXPath, string xmlContent, string nodeValue)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlContent);
            if (xmlDoc == null)
            {
                throw new ArgumentException("xml文本内容错误");
            }
            XmlNode node = xmlDoc.SelectSingleNode(nodeXPath);
            if (node == null)
            {
                throw new ArgumentException(string.Format("没有找到节点：{0}", nodeXPath));
            }
            node.InnerText = nodeValue;
            return xmlDoc.OuterXml;
        }

        /// <summary>
        /// 根据xml的节点路径获取节点值
        /// </summary>
        /// <param name="nodeXPath">节点路径</param>
        /// <param name="xmlFilePath">xml文件路径</param>
        /// <returns>节点值</returns>
        /// <exception cref="ArgumentNullException">参数为空异常</exception>
        /// <exception cref="FileNotFoundException">文件不存在异常</exception>
        internal static string GetNodeByXPath(string nodeXPath, string xmlFilePath = "")
        {
            if (string.IsNullOrEmpty(nodeXPath))
            {
                throw new ArgumentNullException("nodeXPath", "节点路径为空");
            }
            if (string.IsNullOrEmpty(xmlFilePath))
            {
                throw new ArgumentNullException("xmlFilePath", "xml文件路径为空");
            }
            if (!File.Exists(xmlFilePath))
            {
                throw new FileNotFoundException("xml文件不存在");
            }
            string res = string.Empty;
            res = GetNode(nodeXPath, xmlFilePath);
            return res;
        }

        /// <summary>
        /// 根据xml的节点路径设置节点值
        /// </summary>
        /// <param name="nodeXPath">节点路径</param>
        /// <param name="nodeValue">节点值</param>
        /// <param name="xmlFilePath">xml文件路径</param>
        internal static void SetNodeByXPath(string nodeXPath, string nodeValue, string xmlFilePath = "")
        {
            if (string.IsNullOrEmpty(nodeXPath))
            {
                throw new ArgumentNullException("nodeXPath", "节点路径为空");
            }
            if (string.IsNullOrEmpty(xmlFilePath))
            {
                throw new ArgumentNullException("xmlFilePath", "xml文件路径为空");
            }
            xmlFilePath = xmlFilePath.Replace('\\', Path.DirectorySeparatorChar);
            if (!File.Exists(xmlFilePath))
            {
                throw new FileNotFoundException("xml文件不存在");
            }
            SetNode(nodeXPath, xmlFilePath, nodeValue);
        }

        /// <summary>
        /// 根据xml的节点路径设置节点值，并刷新内容
        /// </summary>
        /// <param name="nodeXPath">节点路径</param>
        /// <param name="nodeValue">节点值</param>
        /// <param name="xmlContent">xml文件内容</param>
        internal static string SetNodeByXPathAndRefresh(string nodeXPath, string nodeValue, string xmlContent)
        {
            if (string.IsNullOrEmpty(nodeXPath))
            {
                throw new ArgumentNullException("nodeXPath", "节点路径为空");
            }
            if (string.IsNullOrEmpty(xmlContent))
            {
                throw new ArgumentNullException("xmlContent", "xml文件内容");
            }
            return SetNodeAndRefresh(nodeXPath, xmlContent, nodeValue);
        }

        /// <summary>
        /// xml反序列化
        /// </summary>
        /// <typeparam name="T">要反序列化的类型</typeparam>
        /// <param name="xmlPath">xml文档存储路径</param>
        /// <returns>结果</returns>
        internal static T XmlDeserializeRef<T>(string xmlPath) where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            T res = default(T);
            if (!File.Exists(xmlPath))
            {
                return res;
            }
            using (FileStream fsRead = File.OpenRead(xmlPath))
            {
                res = serializer.Deserialize(fsRead) as T;
                if (res == null)
                {
                    throw new Exception(string.Format("xml反序列化失败：{0}", typeof(T).Name));
                }
            }
            return res;
        }

        /// <summary>
        /// xml反序列化
        /// </summary>
        /// <typeparam name="T">要反序列化的类型</typeparam>
        /// <param name="xmlPath">xml文档存储路径</param>
        /// <returns>结果</returns>
        internal static List<T> XmlDeserializeList<T>(string xmlPath) where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
            List<T> res = default(List<T>);
            if (!File.Exists(xmlPath))
            {
                return res;
            }
            using (FileStream fsRead = File.OpenRead(xmlPath))
            {
                res = serializer.Deserialize(fsRead) as List<T>;
                if (res == null)
                {
                    throw new Exception(string.Format("xml反序列化失败：List<{0}>", typeof(T).Name));
                }
            }
            return res;
        }

        /// <summary>
        /// xml反序列化
        /// </summary>
        /// <typeparam name="T">要反序列化的类型</typeparam>
        /// <param name="xmlPath">xml文档存储路径</param>
        /// <returns>结果</returns>
        internal static T XmlDeserializeVal<T>(string xmlPath) where T : struct
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            T res = default(T);
            if (!File.Exists(xmlPath))
            {
                return res;
            }
            using (FileStream fsRead = File.OpenRead(xmlPath))
            {
                res = (T)serializer.Deserialize(fsRead);
            }
            return res;
        }


        /// <summary>
        /// xml序列化
        /// </summary>
        /// <param name="obj">对象的值</param>
        /// <param name="xmlPath">xml文档存储路径</param>
        internal static void XmlSerialize(object obj, string xmlPath)
        {
            if (obj == null)
            {
                return;
            }
            XmlSerializer serializer = new XmlSerializer(obj.GetType());
            if (!File.Exists(xmlPath))
            {
                CreateDirectory(xmlPath);
            }
            File.Delete(xmlPath);
            using (FileStream fs = new FileStream(xmlPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
            {
                serializer.Serialize(fs, obj);
            }
        }

        /// <summary>
        /// 获取全路径的目录
        /// </summary>
        /// <param name="fullPath">全路径</param>
        /// <returns>目录</returns>
        internal static string GetDirectory(string fullPath)
        {
            return Path.GetDirectoryName(fullPath);
        }

        /// <summary>
        /// 创建路径的目录
        /// </summary>
        /// <param name="path">路径</param>
        internal static void CreateDirectory(string path)
        {
            string fullPath = Path.GetFullPath(path);
            string directory = GetDirectory(fullPath);
            if (string.IsNullOrEmpty(directory))
            {
                return;
            }
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }
        }
    }
}
